package com.kaigejava.spring.circularstudy;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 凯哥Java
 * @description 循环依赖的容器
 * 循环依赖起始就是通过反射方式将反射出来的对象(只是获取到instance对象的)，暴露出来，供依赖的对象使用的
 * @company
 * @since 2022/11/10 12:30
 */
public class MyContainer {

    /**
     * 用来存放提前暴露的对象。也就是半成品的缓存。存放，只是调用了newInstance方法的对象
     * key：类的名字
     * Object：newInstance方法后的对象
     */
    private final static Map<String,Object> singletonObjects = new ConcurrentHashMap<>();

    /**
     * 通过class获取对象
     * @param beanClass
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> T getBean(Class<T> beanClass) throws Exception{
        //1：获取需要实例化的类的名字-作为缓存的key
        String beanName = beanClass.getSimpleName().toLowerCase();
        //2：根据命中，到一级缓存中查询是否存在当前半成品对象
        if(singletonObjects.containsKey(beanName)){
            return (T) singletonObjects.get(beanName);
        }
        //3：如果不存在。就通过反射来实例化对象
        Object obj = beanClass.newInstance();
        //将这个还没有完整创建的对称存储在一级缓存里面，提前暴露出去
        singletonObjects.put(beanName,obj);
        //通过反射，获取到属性。填充属性
        Field[] declaredFields = obj.getClass().getDeclaredFields();
        //循环填充属性
        for (Field field : declaredFields) {
            //针对private修饰符的处理
            field.setAccessible(true);
            //获取到当前字段的类型
            Class<?> fieldClass = field.getType();
            //获取到当前字段类型的简称。
            String fieldBeanName  = fieldClass.getSimpleName().toLowerCase();
            //填充当前属性值。如果一级缓存没有，就递归调用
            field.set(obj,singletonObjects.containsKey(fieldBeanName)?singletonObjects.get(fieldBeanName):getBean(fieldClass));

        }
        //对象所有属性都填充完成之后,返回
        return (T)obj;

    }
}
